
/******************************************************************************
 *
 * jattbak - TODO
 *
 * Author:        Dennis Krzyzaniak
 * E-mail:        ebrosius@netgarage.org
 * Copyright (C): 2011 by Dennis Krzyzaniak
 *
 * This file is part of jattbak.
 *
 * jattbak is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * jattbak is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with jattbak.  If not, see <http://www.gnu.org/licenses/>.
 *
 *****************************************************************************/

/* =========== INCLUDES ==================================================== */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "timer.h"

#include "base_dlist.h"

#include <assert.h>
#include <stdlib.h>

/* =========== MODULE CONFIGURATION ======================================== */

/* =========== DEFINES ===================================================== */

/* =========== DATA TYPES ================================================== */

/** status of timer */
typedef enum {
   /** waiting */
   IDLE,
   /** running */
   ACTIVE,
   /** expired */
   DONE
} jbkTimerState_t;

/** timer */
struct jbkTimer_s {
   /** dlist base node */
   baseDlistNode_t baseNode;
   /** status of timer */
   jbkTimerState_t state;
   /** type of timer */
   jbkTimerType_t type;
   /** time to wait */
   unsigned int time;
   /** relative time to wait */
   unsigned int length;
};

/* =========== GLOBALS ===================================================== */

/** list of timers to handle */
baseDlist_t timerDlist;

/* =========== PRIVATE PROTOTYPES ========================================== */

/* =========== PUBLIC FUNCTIONS ============================================ */

/*---------------------------------------------------------------------------*/
void
jbkTimerInit(
      void
      )
{
   static int initDone = 0;

   if (initDone) {
      return;
   }

   baseDlistInit(&timerDlist);

   initDone = 1;
}
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
int
jbkTimerStart(
      jbkTimer_t* const timer,
      unsigned int mSec,
      jbkTimerType_t timerType
      )
{
   jbkTimer_t* node = NULL;

   assert(timer != NULL);

   if (timer->state == ACTIVE) {
      return -1;
   }

   timer->time = mSec;
   timer->length = mSec;
   timer->state = ACTIVE;

   node = (jbkTimer_t*)baseDlistGetHead(&timerDlist);
   if (node == NULL) {
      baseDlistAddHead(&timerDlist, (baseDlistNode_t*)timer);
      return 0;
   }

   if (timer->length > node->length) {
      timer->length -= node->length;
      while ((node = (jbkTimer_t*)baseDlistGetSuccessor((baseDlistNode_t*)node))
               != NULL) {
         if (timer->length > node->length) {
            timer->length -= node->length;
         } else if (timer->length < node->length) {
            node->length -= timer->length;
            break;
         } else {
            break;
         }
      }
      if (node != NULL) {
         baseDlistInsertBefore(&timerDlist, (baseDlistNode_t*)node,
               (baseDlistNode_t*)timer);
      } else {
         baseDlistAddTail(&timerDlist, (baseDlistNode_t*)timer);
      }
   } else {
      node->length -= mSec;
      baseDlistAddHead(&timerDlist, (baseDlistNode_t*)timer);
   }

   return 0;
}
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
int
jbkTimerWait(
      jbkTimer_t* const timer
      )
{
   assert(timer != NULL);
   return 0;
}
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
void
jbkTimerCancel(
      jbkTimer_t* const timer
      )
{
   jbkTimer_t* node = NULL;

   assert(timer != NULL);

   if (timer->state != ACTIVE) {
      return -1;
   }

   node = (jbkTimer_t*)baseDlistGetSuccessor((baseDlistNode_t*)timer);
   if (node != NULL) {
      node->length += timer->length;
   }
   baseDlistRemove((baseDlistNode_t*)timer);
   timer->state = DONE;
   timer->length = 0;
}
/*---------------------------------------------------------------------------*/

/* =========== PRIVATE FUNCTIONS =========================================== */

/* ========================== END OF FILE ================================== */

/*
 * vim settings, please do not remove!
 * vim:autoindent:
 * vim:ts=3:sw=3:sts=3:expandtab:cindent:tw=75:formatoptions=croql:
 * vim600:foldmethod=syntax:
 */
